package com.zmn.plat.business.impl.pilot;

import com.zmn.common.constant.GlobalConsts;
import com.zmn.common.dictionary.GlobalDict;
import com.zmn.common.utils.date.DateUtil;
import com.zmn.common.utils.reflect.BeanMapper;
import com.zmn.plat.business.interfaces.pilot.ChannelPriceCategoryBService;
import com.zmn.plat.common.constant.OnePriceConsts;
import com.zmn.plat.common.constant.ProductConsts;
import com.zmn.plat.common.exception.PlatException;
import com.zmn.plat.common.util.StringToArrayUtil;
import com.zmn.plat.model.entity.category.BaseCategory;
import com.zmn.plat.model.entity.category.BaseCategoryQuery;
import com.zmn.plat.model.entity.pilot.*;
import com.zmn.plat.model.entity.product.ServProduct;
import com.zmn.plat.model.entity.product.ServProductQuery;
import com.zmn.plat.model.entity.servcategory.ServAssCategoryQuery;
import com.zmn.plat.model.entity.servcategory.ServCategory;
import com.zmn.plat.model.vo.servcategory.CategotyVO;
import com.zmn.plat.model.vo.servcategory.ServAssCategoryVO;
import com.zmn.plat.services.interfaces.category.BaseCategoryService;
import com.zmn.plat.services.interfaces.pilot.ChannelPriceCategoryService;
import com.zmn.plat.services.interfaces.pilot.ChannelPriceCityService;
import com.zmn.plat.services.interfaces.pilot.ChannelPriceService;
import com.zmn.plat.services.interfaces.pilot.ServCityPriceService;
import com.zmn.plat.services.interfaces.product.ServProductService;
import com.zmn.plat.services.interfaces.servcategory.ServAssCategoryService;
import com.zmn.plat.services.interfaces.servcategory.ServCategoryService;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.util.CollectionUtils;

import javax.annotation.Resource;
import java.util.*;
import java.util.stream.Collectors;

/**
 * 类描述：渠道开通分类业务类
 *
 * @author yangshuangping
 * @since 2021/06/28 15:14
 */
@Slf4j
@Service
public class ChannelPriceCategoryBServiceImpl implements ChannelPriceCategoryBService {

    @Resource
    ChannelPriceService channelPriceService;
    @Resource
    ServProductService servProductService;
    @Resource
    ServCategoryService servCategoryService;
    @Resource
    BaseCategoryService baseCategoryService;
    @Resource
    ServCityPriceService servCityPriceService;
    @Autowired
    private ServAssCategoryService servAssCategoryService;
    @Resource
    ChannelPriceCategoryService channelPriceCategoryService;
    @Resource
    ChannelPriceCityService channelPriceCityService;

    @Override
    public void modifyServiceCategory(Integer configId, Integer servCategId, Integer type, Integer showType
            , List<String> categoryIds, String operator) {
        if (configId == null) {
            return;
        }
        // 校验渠道试点配置前台分类
        if (ProductConsts.EC_PRODUCT_TYPE.equals(showType)) {
            judgeUpProduct(servCategId, showType, categoryIds);
            checkCategorySatisfyFaultRule(configId, type, categoryIds);
            // 只有渠道类型的需要校验重复
            if (Objects.equals(OnePriceConsts.CHANNEL_CONFIG, type)) {
                checkCategoryRepeat(configId, servCategId, categoryIds, showType);
            }
        }
        channelPriceCategoryService.deleteByConfigIdAndServCategId(configId, servCategId, type, showType);
        log.info("#deleteByConfigIdAndServCategId#channelId[{}],servCategId[{}]", configId, servCategId);
        if (categoryIds.size() > 0) {
            List<ChannelPriceCategory> insertBatch = categoryIds.stream()
                    .map(categoryId -> StringToArrayUtil.convertStrsToList(categoryId, OnePriceConsts.SPLITER_STRIPING))
                    .filter(ids -> ids.size() == 3)
                    .map(ids -> ChannelPriceCategory.builder()
                            .configId(configId)
                            .type(type)
                            .showType(showType)
                            .servCategId(ids.get(0))
                            .categOneId(ids.get(1))
                            .categId(ids.get(2))
                            .createTime(DateUtil.getNow())
                            .updateTime(DateUtil.getNow())
                            .creater(operator)
                            .updater(operator).build())
                    .collect(Collectors.toCollection(() -> new ArrayList<>(categoryIds.size())));
            channelPriceCategoryService.insertBatchs(insertBatch);

            //  应用分类添加成功后启动配置： 配置类型 1渠道配置 2城市配置
//            if (type.equals(OnePriceConsts.CHANNEL_CONFIG)) {
//                channelPriceService.updateStatusBatch(Arrays.asList(configId), GlobalDict.STATUS_ENABLE, operator);
//            }
            if (type.equals(OnePriceConsts.CITY_CONFIG)) {
                servCityPriceService.updateStatusBatch(Arrays.asList(configId), GlobalDict.STATUS_ENABLE, operator);
            }
        }
    }

    /**
     * 添加应用分类重复校验
     *
     * @param configId    配置Id
     * @param servCategId 服务分类id
     * @param categoryIds 分类id 1001-2001-3001
     * @param showType    产品分类 1后台 2前台
     */
    private void checkCategoryRepeat(Integer configId, Integer servCategId, List<String> categoryIds, Integer showType) {

        // 根据配置id获取配置的城市和类型
        ChannelPrice price = channelPriceService.findById(configId);

        // 判断是否有相同渠道
        ChannelPriceQuery query = new ChannelPriceQuery();
        query.setChannelId(price.getChannelId());
        query.setDelete(GlobalConsts.YES);
        List<ChannelPrice> priceList = Optional.ofNullable(channelPriceService.listByQuery(query)).orElse(new ArrayList<>());
        if (priceList.size() == OnePriceConsts.LIST_COUNT) {
            return;
        }
        // 渠道相同，是否有相同的类型
        priceList = priceList.stream()
                .filter(x -> Objects.equals(price.getType(), x.getType()))
                .collect(Collectors.toList());

        if (CollectionUtils.isEmpty(priceList)) {
            return;
        }
        // 是否存在相同的城市
        List<Integer> channelPriceIdList = priceList.stream()
                .map(ChannelPrice::getChannelPriceId)
                .collect(Collectors.toList());

        ChannelPriceCityQuery cityQuery = new ChannelPriceCityQuery();
        cityQuery.setChannelPriceIdList(channelPriceIdList);
        List<ChannelPriceCity> list = channelPriceCityService.listByQuery(cityQuery);

        // 判断是否有相同的执行或不执行省
        List<ChannelPriceCity> provinceIds = gainRepeatValue(list, price);
        if (CollectionUtils.isEmpty(provinceIds)) {
            return;
        }
        // 判断应用分类是否有相同
        channelPriceIdList = provinceIds.stream()
                .map(ChannelPriceCity::getChannelPriceId)
                .distinct()
                .collect(Collectors.toList());

        ChannelPriceCategoryQuery categoryQuery = new ChannelPriceCategoryQuery();
        categoryQuery.setConfigIdList(channelPriceIdList);
        categoryQuery.setShowType(showType);
        List<ChannelPriceCategory> categoryList = channelPriceCategoryService.listByQuery(categoryQuery);

        if (CollectionUtils.isEmpty(categoryList)) {
            return;
        }
        categoryList = categoryList.stream()
                .filter(x -> categoryIds.contains(servToStr(x)))
                .collect(Collectors.toList());

        if (CollectionUtils.isEmpty(categoryList)) {
            return;
        }
        // 存在重复的分类这提示不允许添加
        ServCategory servCategory = servCategoryService.findByKey(servCategId);
        List<Integer> CategoryIds = categoryList.stream()
                .map(ChannelPriceCategory::getCategId)
                .distinct()
                .collect(Collectors.toList());

        BaseCategoryQuery baseCategoryQuery = new BaseCategoryQuery();
        baseCategoryQuery.setCategIds(CategoryIds);
        List<BaseCategory> baseCategories = baseCategoryService.listByQuery(baseCategoryQuery);

        if (!CollectionUtils.isEmpty(baseCategories)) {
            StringBuffer tips = new StringBuffer();
            for (int i = 0; i < baseCategories.size(); i++) {
                tips.append(servCategory.getShowName())
                        .append(OnePriceConsts.SPLITER_STRIPING)
                        .append(baseCategories.get(i).getParentName())
                        .append(OnePriceConsts.SPLITER_STRIPING)
                        .append(baseCategories.get(i).getName())
                        .append(i < baseCategories.size() - 1 ? "、" : GlobalConsts.SPLITER_EMPTY);
            }
            throw new PlatException(String.format("【<span style='color:red;'>%s</span>】已被当前渠道、城市下其它配置选择，请检查后重新提交！", tips));
        }
    }

    /**
     * 判断是否存在重复的执行城市或不执行城市
     *
     * @param list  渠道试点执行城市list
     * @param price 试点配置
     */
    private List<ChannelPriceCity> gainRepeatValue(List<ChannelPriceCity> list, ChannelPrice price) {
        List<ChannelPriceCity> province = new ArrayList<>();
        // 获取当前渠道试点省级列表
        List<Integer> provinceIds = list.stream()
                .filter(x -> x.getChannelPriceId().equals(price.getChannelPriceId()))
                .map(ChannelPriceCity::getProvinceId).distinct().collect(Collectors.toList());
        // 获取当前渠道试点市级列表
        List<Integer> cityIds = list.stream()
                .filter(x -> x.getChannelPriceId().equals(price.getChannelPriceId()))
                .map(ChannelPriceCity::getCityId).distinct().collect(Collectors.toList());
        // 排除当前试点数据
        list = list.stream()
                .filter(x -> !Objects.equals(x.getChannelPriceId(), price.getChannelPriceId()))
                .collect(Collectors.toList());
        list.stream().filter(x -> provinceIds.contains(x.getProvinceId())).forEach(x -> {
            if (Objects.isNull(x.getCityId())) {
                province.add(x);
            }
            if (cityIds.contains(null)) {
                province.add(x);
            }
            if (Objects.nonNull(x.getCityId()) && cityIds.contains(x.getCityId())) {
                province.add(x);
            }
        });
        return province;
    }

    /**
     * 需要校验 所选择的服务分类+二级产品分类下是否有已上架的前台产品
     *
     * @param servCategId 服务分类ID
     * @param showType    产品分类：后端产品,前端产品
     * @param categoryIds 服务类型ids
     */
    private void judgeUpProduct(Integer servCategId, Integer showType, List<String> categoryIds) {

        ServProductQuery servProductQuery = new ServProductQuery();
        servProductQuery.setShowType(showType);
        servProductQuery.setServCategId(servCategId);
        servProductQuery.setStatus(GlobalConsts.YES);
        List<ServProduct> servProducts = servProductService.listByQuery(servProductQuery);

        List<String> upProductCategIds = servProducts.stream()
                .map(item -> servToStr(item))
                .collect(Collectors.toList());

        List<String> tipsCategIds = categoryIds.stream()
                .filter(item -> !upProductCategIds.contains(item))
                .collect(Collectors.toList());

        List<Integer> twoCategoryIds;
        ServCategory servCategory = servCategoryService.findByKey(servCategId);
        String servCategName = GlobalConsts.SPLITER_EMPTY;

        if (servCategory != null) {
            servCategName = showType.equals(ProductConsts.ERP_PRODUCT_TYPE) ? servCategory.getName() : servCategory.getShowName();
        }

        if (!CollectionUtils.isEmpty(tipsCategIds)) {
            twoCategoryIds = tipsCategIds.stream()
                    .map(x -> StringToArrayUtil.convertStrsToList(x, OnePriceConsts.SPLITER_STRIPING))
                    .filter(x -> x.size() == 3)
                    .map(x -> x.get(2))
                    .collect(Collectors.toList());

            BaseCategoryQuery baseCategoryQuery = new BaseCategoryQuery();
            baseCategoryQuery.setCategIds(twoCategoryIds);
            List<BaseCategory> baseCategories = baseCategoryService.listByQuery(baseCategoryQuery);

            StringBuffer tips = new StringBuffer();
            for (int i = 0; i < baseCategories.size(); i++) {
                tips.append(servCategName)
                        .append(OnePriceConsts.SPLITER_STRIPING)
                        .append(baseCategories.get(i).getParentName())
                        .append(OnePriceConsts.SPLITER_STRIPING)
                        .append(baseCategories.get(i).getName())
                        .append(i < baseCategories.size() - 1 ? "、" : GlobalConsts.SPLITER_EMPTY);
            }
            String productTipStr = showType.equals(ProductConsts.ERP_PRODUCT_TYPE) ? "后台产品" : "前台产品";
            throw new PlatException(String.format("【<span style='color:red;'>%s</span>】产品分类下无上架的%s，请设置", tips, productTipStr));
        }
    }


    /**
     * 校验渠道配置，城市配置 开通前台品类是否满足计价器关系
     *
     * @param type 配置类型 1渠道配置 2城市配置
     */
    private void checkCategorySatisfyFaultRule(Integer configId, Integer type, List<String> showCategoryIds) {

        ChannelPrice channelPrice = channelPriceService.findById(configId);
        Integer channelId = channelPrice != null && channelPrice.getChannelId() != null ? channelPrice.getChannelId() : 0;
        Boolean flag = Objects.equals(OnePriceConsts.CHANNEL_TYPE, type) && channelPrice != null && OnePriceConsts.TARIFF != channelPrice.getType();
        if (flag) {
            return;
        }
        if (Objects.equals(OnePriceConsts.CITY_TYPE, type)) {
            ServCityPrice servCityPrice = servCityPriceService.findById(configId);
            if (servCityPrice != null && OnePriceConsts.TARIFF != servCityPrice.getType()) {
                return;
            }
        }
        List<ServProduct> servProducts = servProductService.listShowProductSatisfyFaultRule(channelId);
        ServAssCategoryQuery showCategoryQuery = new ServAssCategoryQuery();
        showCategoryQuery.setCategOneStatus(GlobalConsts.YES);
        showCategoryQuery.setCategTwoStatus(GlobalConsts.YES);
        showCategoryQuery.setServCategShowStatus(GlobalConsts.YES);
        showCategoryQuery.setShowType(ProductConsts.EC_PRODUCT_TYPE);
        // 启用的前台分类
        Map<String, ServAssCategoryVO> showCategoryMap = servAssCategoryService.listByQuery(showCategoryQuery).stream()
                .collect(Collectors.toMap(item -> servToStr(item), item -> item, (p, u) -> p));

        Map<String, List<ServProduct>> resultMap = servProducts.stream()
                .collect(Collectors.groupingBy(item -> servToStr(item)));

        StringBuffer stringBuffer = new StringBuffer();
        for (String categoryId : showCategoryIds) {
            ServAssCategoryVO showCategory = showCategoryMap.get(categoryId);
            if (resultMap.get(categoryId) == null) {
                stringBuffer.append(showCategory.getServCategName())
                        .append(OnePriceConsts.SPLITER_STRIPING)
                        .append(showCategory.getCategOneName())
                        .append(OnePriceConsts.SPLITER_STRIPING)
                        .append(showCategory.getCategName())
                        .append("、");
            }
        }
        if (stringBuffer.toString().length() > 0) {
            stringBuffer.deleteCharAt(stringBuffer.length() - 1);
            throw new PlatException(String.format(
                    "【<span style='color:red;'>%s</span>】前台产品分类下：必须存在可用于计价器的关系，需满足以下条件：" +
                            "<br>1、上架的前台产品关联的上架的后台产品至少有一个 计价器状态是启用的" +
                            "<br>2、该后台产品至少关联一个已上架的计价器产品" +
                            "<br>3、该后台产品的保外计价器价格表：价格表为启用状态并且有启用中的项目",
                    stringBuffer));
        }
    }

    /**
     * 将服务分类转为以“-” 分隔的字符串
     *
     * @param bean 实体
     * @param <T>  类型
     * @return 1001-2001-2003
     */
    @Override
    public <T> String servToStr(T bean) {
        CategotyVO map = Optional.ofNullable(BeanMapper.map(bean, CategotyVO.class)).orElse(null);
        return Objects.isNull(map) ? "" : new StringBuffer().append(map.getServCategId())
                .append(OnePriceConsts.SPLITER_STRIPING)
                .append(map.getCategOneId())
                .append(OnePriceConsts.SPLITER_STRIPING)
                .append(map.getCategId()).toString();

    }
}
